﻿using System;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.LinearReferencing
{
	public class LengthIndexOfPoint
	{
		public static double IndexOf(IGeometry linearGeom, Coordinate inputPt)
		{
			return new LengthIndexOfPoint(linearGeom).IndexOf(inputPt);
		}

		public static double IndexOfAfter(IGeometry linearGeom, Coordinate inputPt, double minIndex)
		{
			return new LengthIndexOfPoint(linearGeom).IndexOfAfter(inputPt, minIndex);
		}

		public LengthIndexOfPoint(IGeometry linearGeom)
		{
			this._linearGeom = linearGeom;
		}

		public double IndexOf(Coordinate inputPt)
		{
			return this.IndexOfFromStart(inputPt, -1.0);
		}

		public double IndexOfAfter(Coordinate inputPt, double minIndex)
		{
			if (minIndex < 0.0)
			{
				return this.IndexOf(inputPt);
			}
			double length = this._linearGeom.Length;
			if (length < minIndex)
			{
				return length;
			}
			double num = this.IndexOfFromStart(inputPt, minIndex);
			Assert.IsTrue(num >= minIndex, "computed index is before specified minimum index");
			return num;
		}

		private double IndexOfFromStart(Coordinate inputPt, double minIndex)
		{
			double num = double.MaxValue;
			double result = minIndex;
			double num2 = 0.0;
			LineSegment lineSegment = new LineSegment();
			LinearIterator linearIterator = new LinearIterator(this._linearGeom);
			while (linearIterator.HasNext())
			{
				if (!linearIterator.IsEndOfLine)
				{
					lineSegment.P0 = linearIterator.SegmentStart;
					lineSegment.P1 = linearIterator.SegmentEnd;
					double num3 = lineSegment.Distance(inputPt);
					double num4 = LengthIndexOfPoint.SegmentNearestMeasure(lineSegment, inputPt, num2);
					if (num3 < num && num4 > minIndex)
					{
						result = num4;
						num = num3;
					}
					num2 += lineSegment.Length;
				}
				linearIterator.Next();
			}
			return result;
		}

		private static double SegmentNearestMeasure(LineSegment seg, Coordinate inputPt, double segmentStartMeasure)
		{
			double num = seg.ProjectionFactor(inputPt);
			if (num <= 0.0)
			{
				return segmentStartMeasure;
			}
			if (num <= 1.0)
			{
				return segmentStartMeasure + num * seg.Length;
			}
			return segmentStartMeasure + seg.Length;
		}

		private readonly IGeometry _linearGeom;
	}
}
